#ifndef __CM_NAT_ICE_LINK_H__
#define __CM_NAT_ICE_LINK_H__

#include "Link.h"
#include "Candidate.h"
#include "StunAgent.h"
#include "cm_base/UDPPort.h"
#include "Poco/Mutex.h"
#include "Poco/Net/IPAddress.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/NetworkInterface.h"

using Poco::Mutex;
using Poco::Net::IPAddress;
using Poco::Net::SocketReactor;
using Poco::Net::NetworkInterface;

namespace cm_nat
{  
    class IceLink;
    class IceLinkPool;

    class IceLinkListener
    {
    public:
        virtual void onReceive(IceLink* link, ByteBuffer* data) =0;
        virtual void onLinkState( IceLink* link, int linkState ) =0;
    };

    class IceLink: public Link, public UDPPortListener, public StunAgentListener
    {
    public:
        IceLink(IceLinkPool* parent, ByteBufferPool* p_pool, SocketReactor* reactor, BaseTimer* p_timer);
        virtual ~IceLink();

        int setStunAddress(SocketAddress stun);

        int setup( IPAddress hostIP );
        //rebind to stun
        int reset();
        
        void registerListener(IceLinkListener*  p_listener);

        int setPeerAddress(SocketAddress peer);

        SocketAddress getHostAddress();
        SocketAddress getPeerAddress();
        SocketAddress getStunReflexAddress();
        SocketAddress getPeerReflexAddress();

        void checkConnection(SocketAddress peer);

        //from Link
        int send(ByteBuffer* data) ;

        //from UDPPortListener
        void onReceive(UDPPort*p_port, ByteBuffer* p_data);

        //from StunAgentListener
        void onToSend(StunAgent* p_agent, ByteBuffer* data, const SocketAddress& sa);
        void onCheckResult(StunAgent* p_agent, int result);

        int getLinkState();

        enum LinkState{
            STATE_NULL,
            STATE_START_STUN_CHECK,
            STATE_KEEP_STUN_CHECK,
            STATE_KEEP_STUN_CHECK_FAIL,
            STATE_START_PEER_CHECK,
            STATE_KEEP_PEER_CHECK,
            STATE_KEEP_PEER_CHECK_FAIL
        };

        enum
        {
            CHECK_RES_STUN_CHECK_FAIL,   //connect fail
            CHECK_RES_STUN_CHECK_SUCCESS,//connection setup
            CHECK_RES_STUN_KEEP_FAIL,

            CHECK_RES_PEER_CHECK_FAIL,
            CHECK_RES_PEER_CHECK_SUCCESS,
            CHECK_RES_PEER_KEEP_FAIL
        };
        
    protected:
        ByteBufferPool* m_bufferPool;
        SocketReactor* m_reactor;

        IceLinkListener* m_listener ;

        UDPPort* m_port;

        StunAgent* m_agent;
        SocketAddress m_stunAddress;

        SocketAddress m_peerAddress;
        SocketAddress m_hostAddress;
        SocketAddress m_stunReflexAddress;
        SocketAddress m_peerReflexAddress;

        BaseTimer* m_timer;

        LinkState m_linkState;

        IceLinkPool* m_linkPool;

        friend class IceLinkPool;
    };

    typedef std::list<IceLink*> IceLinkList;
}

#endif